From 89e23317ba22d6de3f3733b2624f2d75d0d06201 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 9 Jan 2006 12:25:05 +0100 Subject: [PATCH] Fix context_switch(). It is necessary to set_current() and then check curr_vcpu all with interrupts disabled. This in turn requires us to hoist the heck of next's vcpu_dirty_cpumask as sending the flush IPI needs us to have interrupts enabled to avoid deadlock. Signed-off-by: Keir Fraser --- xen/arch/x86/domain.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index e44c79a1dd..0d6517038f 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -689,6 +689,9 @@ static void __context_switch(void) struct vcpu *p = percpu_ctxt[cpu].curr_vcpu; struct vcpu *n = current; + ASSERT(p != n); + ASSERT(cpus_empty(n->vcpu_dirty_cpumask)); + if ( !is_idle_domain(p->domain) ) { memcpy(&p->arch.guest_context.user_regs, @@ -748,24 +751,31 @@ static void __context_switch(void) void context_switch(struct vcpu *prev, struct vcpu *next) { unsigned int cpu = smp_processor_id(); + cpumask_t dirty_mask = next->vcpu_dirty_cpumask; ASSERT(local_irq_is_enabled()); + /* Allow at most one CPU at a time to be dirty. */ + ASSERT(cpus_weight(dirty_mask) <= 1); + if ( unlikely(!cpu_isset(cpu, dirty_mask) && !cpus_empty(dirty_mask)) ) + { + /* Other cpus call __sync_lazy_execstate from flush ipi handler. */ + flush_tlb_mask(dirty_mask); + } + + local_irq_disable(); + set_current(next); - if ( (percpu_ctxt[cpu].curr_vcpu != next) && - !is_idle_domain(next->domain) ) + if ( (percpu_ctxt[cpu].curr_vcpu == next) || is_idle_domain(next->domain) ) + { + local_irq_enable(); + } + else { - /* This may happen if next has been migrated by the scheduler. */ - if ( unlikely(!cpus_empty(next->vcpu_dirty_cpumask)) ) - { - ASSERT(!cpu_isset(cpu, next->vcpu_dirty_cpumask)); - sync_vcpu_execstate(next); - ASSERT(cpus_empty(next->vcpu_dirty_cpumask)); - } - - local_irq_disable(); __context_switch(); + + /* Re-enable interrupts before restoring state which may fault. */ local_irq_enable(); if ( VMX_DOMAIN(next) ) -- 2.30.2